home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 009a / tde221.zip / MACRO.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  26KB  |  738 lines

  1. /*
  2.  * The "macro" routines in TDE are not really macro routines in the classical
  3.  * sense.  In TDE, "macros" are just recordings of key sequences.  But,
  4.  * actually, I find the ability to record and playback keystrokes generally
  5.  * more useful than writing a macro.  Being that I'm so stupid, it takes me
  6.  * half the morning to write and half the afternoon to debug a simple classical
  7.  * macro.  For most of my routine, little jobs, I find it more convenient
  8.  * to record my keystrokes and playback those keystrokes at appropriate places
  9.  * in a file.  It just seems easier for me to "teach" the editor what to do
  10.  * rather than "instruct" the editor what to do.
  11.  *
  12.  * New editor name:  TDE, the Thomson-Davis Editor.
  13.  * Author:           Frank Davis
  14.  * Date:             June 5, 1991, version 1.0
  15.  * Date:             July 29, 1991, version 1.1
  16.  * Date:             October 5, 1991, version 1.2
  17.  * Date:             January 20, 1992, version 1.3
  18.  * Date:             February 17, 1992, version 1.4
  19.  * Date:             April 1, 1992, version 1.5
  20.  * Date:             June 5, 1992, version 2.0
  21.  * Date:             October 31, 1992, version 2.1
  22.  * Date:             April 1, 1993, version 2.2
  23.  *
  24.  * This modification of Douglas Thomson's code is released into the
  25.  * public domain, Frank Davis.  You may distribute it freely.
  26.  */
  27.  
  28.  
  29. #include "tdestr.h"             /* tde types */
  30. #include "common.h"
  31. #include "define.h"
  32. #include "tdefunc.h"
  33.  
  34.  
  35. /*
  36.  *              keystroke record functions
  37.  */
  38.  
  39. /*
  40.  * Name:    record_on_off
  41.  * Purpose: save keystrokes in keystroke buffer
  42.  * Date:    April 1, 1992
  43.  * Passed:  window:  pointer to current window
  44.  * Notes:   -1 in .next field indicates the end of a recording
  45.  *          -1 in .key field indicates the initial, unassigned macro key
  46.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  47.  */
  48. int  record_on_off( WINDOW *window )
  49. {
  50. register int next;
  51. int  prev;
  52. int  line;
  53. int  key;
  54. int  func;
  55. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  56.  
  57.    mode.record = !mode.record;
  58.    if (mode.record == TRUE) {
  59.       line = window->bottom_line;
  60.       show_avail_strokes( );
  61.       save_screen_line( 0, line, line_buff );
  62.       /*
  63.        * press key that will play back recording
  64.        */
  65.       set_prompt( main11, line );
  66.  
  67.       /*
  68.        * get the candidate macro key and look up the function assigned to it.
  69.        */
  70.       key = getkey( );
  71.       func = getfunc( key );
  72.  
  73.       /*
  74.        * the key must be an unused, recognized function key or a function
  75.        *  key assigned to a previously defined macro.  we also need room
  76.        *  in the macro structure.
  77.        */
  78.       if (key <= 256 || (func != 0 && func != PlayBack)) {
  79.          /*
  80.           * cannot assign a recording to this key
  81.           */
  82.          error( WARNING, line, main12 );
  83.          mode.record = FALSE;
  84.       } else if (g_status.stroke_count == 0) {
  85.          /*
  86.           * no more room in recording buffer
  87.           */
  88.          error( WARNING, line, main13 );
  89.          mode.record = FALSE;
  90.       } else {
  91.  
  92.          /*
  93.           * everything is everything so far, just check for a prev macro
  94.           */
  95.          prev = OK;
  96.          if (func == PlayBack) {
  97.             /*
  98.              * overwrite recording (y/n)?
  99.              */
  100.             set_prompt( main14, line );
  101.             if (get_yn( ) == A_NO) {
  102.                prev = ERROR;
  103.                mode.record = FALSE;
  104.             }
  105.          }
  106.          if (prev == OK) {
  107.             g_status.recording_key = key;
  108.             next = macro.first_stroke[key-256];
  109.  
  110.             /*
  111.              * if key has already been assigned to a macro, clear macro def.
  112.              */
  113.             if (next != STROKE_LIMIT+1) {
  114.                do {
  115.                   prev = next;
  116.                   next = macro.strokes[next].next;
  117.                   macro.strokes[prev].key  = MAX_KEYS+1;
  118.                   macro.strokes[prev].next = STROKE_LIMIT+1;
  119.                   ++g_status.stroke_count;
  120.                } while (next != -1);
  121.                show_avail_strokes( );
  122.             }
  123.  
  124.             /*
  125.              * find the first open space and initialize
  126.              */
  127.             for (next=0; macro.strokes[next].next != STROKE_LIMIT+1;)
  128.                next++;
  129.             macro.first_stroke[key-256] = next;
  130.             macro.strokes[next].key  = -1;
  131.             macro.strokes[next].next = -1;
  132.             key_func.key[key-256] = PlayBack;
  133.             /*
  134.              * recording
  135.              */
  136.             s_output( main15, g_display.mode_line, 22,
  137.                       g_display.mode_color | 0x80 );
  138.          }
  139.       }
  140.       restore_screen_line( 0, line, line_buff );
  141.    }
  142.  
  143.    /*
  144.     * the flashing "Recording" and the stroke count write over the modes.
  145.     *  when we get thru defining a macro, redisplay the modes.
  146.     */
  147.    if (mode.record == FALSE) {
  148.       memset( line_buff, ' ', 36 );
  149.       line_buff[36] = '\0';
  150.       s_output( line_buff, g_display.mode_line, 22, g_display.mode_color );
  151.       show_tab_modes( );
  152.       show_indent_mode( );
  153.       show_sync_mode( );
  154.       show_search_case( );
  155.       show_wordwrap_mode( );
  156.  
  157.       /*
  158.        * let's look at the macro.  if the first .key of the macro is
  159.        *  still -1, which is the initial unassigned key in a macro, reset
  160.        *  the macro so other keys may be assigned to this node.
  161.        */
  162.       key = g_status.recording_key;
  163.       if (key != 0) {
  164.          next = macro.first_stroke[key-256];
  165.          if (macro.strokes[next].key == -1) {
  166.             macro.strokes[next].key  = MAX_KEYS+1;
  167.             macro.strokes[next].next = STROKE_LIMIT+1;
  168.             macro.first_stroke[key-256] = STROKE_LIMIT+1;
  169.             if (getfunc( key ) == PlayBack)
  170.                key_func.key[key-256] = 0;
  171.          }
  172.       }
  173.       g_status.recording_key = 0;
  174.    }
  175.    return( OK );
  176. }
  177.  
  178.  
  179. /*
  180.  * Name:    record_keys
  181.  * Purpose: save keystrokes in keystroke buffer
  182.  * Date:    April 1, 1992
  183.  * Passed:  line: line to display prompts
  184.  * Notes:   -1 in .next field indicates the end of a recording
  185.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  186.  */
  187. void record_keys( int line )
  188. {
  189. register int next;
  190. register int prev;
  191. int  key;
  192. int  func;
  193.  
  194.    if (mode.record == TRUE) {
  195.       if (g_status.stroke_count == 0)
  196.          /*
  197.           * no more room in recording buffer
  198.           */
  199.          error( WARNING, line, main13 );
  200.       else {
  201.          key = g_status.key_pressed;
  202.          func = getfunc( key );
  203.          if (func != RecordMacro && func != SaveMacro && func != LoadMacro &&
  204.              func != ClearAllMacros) {
  205.  
  206.             /*
  207.              * a -1 in the next field marks the end of the keystroke recording.
  208.              */
  209.             next = macro.first_stroke[g_status.recording_key - 256];
  210.             if (macro.strokes[next].next != STROKE_LIMIT+1) {
  211.                while (macro.strokes[next].next != -1)
  212.                   next = macro.strokes[next].next;
  213.             }
  214.             prev = next;
  215.  
  216.             /*
  217.              * now find an open space to record the current key.
  218.              */
  219.             if (macro.strokes[next].key != -1) {
  220.                for (; next < STROKE_LIMIT &&
  221.                             macro.strokes[next].next != STROKE_LIMIT+1;)
  222.                   next++;
  223.                if (next == STROKE_LIMIT) {
  224.                   for (next=0; next < prev &&
  225.                                macro.strokes[next].next != STROKE_LIMIT+1;)
  226.                      next++;
  227.                }
  228.             }
  229.             if (next == prev && macro.strokes[prev].key != -1)
  230.                /*
  231.                 * no more room in recording buffer
  232.                 */
  233.                error( WARNING, line, main13 );
  234.             else {
  235.             /*
  236.              * next == prev if we are recording the initial macro node.
  237.              */
  238.                macro.strokes[prev].next = next;
  239.                macro.strokes[next].next = -1;
  240.                macro.strokes[next].key  = key;
  241.                g_status.stroke_count--;
  242.                show_avail_strokes( );
  243.             }
  244.          }
  245.       }
  246.    }
  247. }
  248.  
  249.  
  250. /*
  251.  * Name:    show_avail_strokes
  252.  * Purpose: show available free key strokes in lite bar at bottom of screen
  253.  * Date:    April 1, 1992
  254.  */
  255. void show_avail_strokes( void )
  256. {
  257. char strokes[MAX_COLS];
  258.  
  259.    s_output( main18, g_display.mode_line, 33, g_display.mode_color );
  260.    itoa( g_status.stroke_count, strokes, 10 );
  261.    s_output( "      ", g_display.mode_line, 51, g_display.mode_color );
  262.    s_output( strokes, g_display.mode_line, 51, g_display.mode_color );
  263. }
  264.  
  265.  
  266. /*
  267.  * Name:    save_strokes
  268.  * Purpose: save strokes to a file
  269.  * Date:    April 1, 1992
  270.  * Passed:  window:  pointer to current window
  271.  */
  272. int  save_strokes( WINDOW *window )
  273. {
  274. FILE *fp;                       /* file to be written */
  275. char name[MAX_COLS+2];          /* file name */
  276. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  277. register int rc;
  278. int  prompt_line;
  279. int  fattr;
  280.  
  281.    name[0] = '\0';
  282.    prompt_line = window->bottom_line;
  283.    save_screen_line( 0, prompt_line, line_buff );
  284.    /*
  285.     * name for macro file
  286.     */
  287.    if ((rc = get_name( main19, prompt_line, name,
  288.                  g_display.message_color )) == OK  &&  *name != '\0') {
  289.  
  290.       /*
  291.        * make sure it is OK to overwrite any existing file
  292.        */
  293.       rc = get_fattr( name, &fattr );
  294.       if (rc == OK) {
  295.          /*
  296.           * overwrite existing file
  297.           */
  298.          set_prompt( main20, prompt_line );
  299.          if (get_yn( ) != A_YES  ||  change_mode( name, prompt_line ) == ERROR)
  300.             rc = ERROR;
  301.       }
  302.       if (rc != ERROR) {
  303.          if ((fp = fopen( name, "wb" )) != NULL) {
  304.             fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  305.             fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  306.             fclose( fp );
  307.          }
  308.       }
  309.    }
  310.    restore_screen_line( 0, prompt_line, line_buff );
  311.    return( OK );
  312. }
  313.  
  314.  
  315. /*
  316.  * Name:    load_strokes
  317.  * Purpose: load strokes from a file
  318.  * Date:    April 1, 1992
  319.  * Passed:  window:  pointer to current window
  320.  * Notes:   show the user a file pick list.  I can never remember macro
  321.  *           file names or the directory in which they hide.  might as well
  322.  *           give the user a file pick list.
  323.  */
  324. int  load_strokes( WINDOW *window )
  325. {
  326. register FILE *fp;      /* file to be read */
  327. char dname[MAX_COLS];   /* directory search pattern */
  328. char stem[MAX_COLS];    /* directory stem */
  329. register int rc;
  330.  
  331.    dname[0] = '\0';
  332.    /*
  333.     * search path for macro file
  334.     */
  335.    if (get_name( main21, window->bottom_line, dname,
  336.                  g_display.message_color ) == OK  &&  *dname != '\0') {
  337.       if (validate_path( dname, stem ) == OK) {
  338.          rc = list_and_pick( dname, stem, window );
  339.  
  340.          /*
  341.           * if everything is everything, load in the file selected by user.
  342.           */
  343.          if (rc == OK) {
  344.             if ((fp = fopen( dname, "rb" )) != NULL && ceh.flag != ERROR) {
  345.                fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  346.                fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  347.                fclose( fp );
  348.             }
  349.             if (ceh.flag == OK)
  350.                connect_macros( );
  351.          }
  352.       } else
  353.          /*
  354.           * invalid path or file name
  355.           */
  356.          error( WARNING, window->bottom_line, main22 );
  357.    }
  358.    return( OK );
  359. }
  360.  
  361.  
  362. /*
  363.  * Name:    clear_macro
  364.  * Purpose: reset all macro buffers, pointers, functions.
  365.  * Date:    April 1, 1992
  366.  * Notes:   reset the available macro stroke count.  reset all fields in
  367.  *           macro structure.  clear any keys assigned to macros in the
  368.  *           function assignment array.
  369.  */
  370. int  clear_macros( WINDOW *arg_filler )
  371. {
  372. register int i;
  373.  
  374.    g_status.stroke_count = STROKE_LIMIT;
  375.    for (i=0; i<STROKE_LIMIT; i++) {
  376.       macro.strokes[i].next = STROKE_LIMIT+1;
  377.       macro.strokes[i].key  = MAX_KEYS+1;
  378.    }
  379.    for (i=0; i<MAX_KEYS; i++) {
  380.       macro.first_stroke[i] = STROKE_LIMIT+1;
  381.       if (key_func.key[i] == PlayBack)
  382.          key_func.key[i] = 0;
  383.    }
  384.    return( OK );
  385. }
  386.  
  387.  
  388. /*
  389.  * Name:    connect_macros
  390.  * Purpose: hook up all (if any) macros to the function key definition table
  391.  * Date:    April 1, 1992
  392.  * Notes:   we need to connect all macro definitions to the key definition
  393.  *           table in the startup routine or when we read in a new macro
  394.  *           definition file.  the predefined func assignments take
  395.  *           precedence over macro definitions.
  396.  */
  397. void connect_macros( void )
  398. {
  399. register int i;
  400.  
  401.    /*
  402.     * reset the key function assignment array.  initially, no keys may be
  403.     *  assigned to a macro.
  404.     */
  405.    for (i=0; i<MAX_KEYS; i++)
  406.       if (key_func.key[i] == PlayBack)
  407.          key_func.key[i] = 0;
  408.  
  409.    /*
  410.     * now, find out how many free keystrokes are in the macro structure.
  411.     */
  412.    g_status.stroke_count = 0;
  413.    for (i=0; i<STROKE_LIMIT; i++)
  414.       if (macro.strokes[i].next == STROKE_LIMIT+1)
  415.          ++g_status.stroke_count;
  416.  
  417.    /*
  418.     * go thru the first stroke list to see if any key has been assigned to
  419.     *  a macro and connect the macro def to the key.  predefined function
  420.     *  assignments take precedence over macros.
  421.     */
  422.    for (i=0; i<MAX_KEYS; i++) {
  423.       if (macro.first_stroke[i] != STROKE_LIMIT+1)
  424.          if (key_func.key[i] == 0)
  425.             key_func.key[i] = PlayBack;
  426.    }
  427. }
  428.  
  429.  
  430. /*
  431.  *              keystroke play back functions
  432.  */
  433.  
  434.  
  435. /*
  436.  * Name:    play_back
  437.  * Purpose: play back a series of keystrokes assigned to key
  438.  * Date:    April 1, 1992
  439.  * Notes:   go thru the macro key list playing back the recorded keystrokes.
  440.  *          to let macros call other macros, we have to 1) save the next
  441.  *           keystroke of the current macro in a stack, 2) execute the
  442.  *           the called macro, 3) pop the key that saved by the calling
  443.  *           macro, 4) continue executing the macro, beginning with the
  444.  *           key we just popped.
  445.  *          use a local stack to store keys.  currently, there is room
  446.  *           for 256 keys -- should be enough room for most purposes.
  447.  */
  448. int  play_back( WINDOW *window )
  449. {
  450. int  key;
  451. int  rc = OK;
  452. int  popped;            /* flag is set when macro is popped */
  453.  
  454.    /*
  455.     * if we are recording a macro, let's just return if we do a recursive
  456.     *  definition.  Otherwise, we end up executing our recursive macro
  457.     *  while we are defining it.
  458.     */
  459.    if (mode.record == TRUE && g_status.key_pressed == g_status.recording_key)
  460.       rc = ERROR;
  461.    else {
  462.  
  463.       /*
  464.        * set the global macro flags, so other routines will know
  465.        *  if a macro is executing.
  466.        * set the stack_pointer to "empty" or -1.  initialize the popped
  467.        *  flag to FALSE being that we haven't popped any thing off the stack,
  468.        *  yet.
  469.        */
  470.       g_status.macro_executing = TRUE;
  471.       g_status.mstack_pointer  = -1;
  472.       popped = FALSE;
  473.       rc = OK;
  474.       while (rc == OK) {
  475.  
  476.          /*
  477.           * the first time thru the loop, popped is FALSE.  some lint
  478.           *  utilities may complain about key being used but not defined.
  479.           */
  480.          if (popped == FALSE) {
  481.  
  482.             /*
  483.              * find the first keystroke in the macro.  when we pop the stack,
  484.              *  all this stuff is reset by the pop -- do not reset it again.
  485.              */
  486.             g_status.macro_next = macro.first_stroke[g_status.key_pressed-256];
  487.             g_status.current_macro = g_status.key_pressed;
  488.             key = macro.strokes[g_status.macro_next].key;
  489.          }
  490.          popped = FALSE;
  491.          if (key != MAX_KEYS+1  &&  key != -1) {
  492.             do {
  493.  
  494.                /*
  495.                 * set up all editor variables as if we were entering
  496.                 *  keys from the keyboard.
  497.                 */
  498.                window = g_status.current_window;
  499.                display_dirty_windows( window );
  500.                ceh.flag = OK;
  501.                g_status.key_pressed = macro.strokes[g_status.macro_next].key;
  502.                g_status.command = getfunc( g_status.key_pressed );
  503.                if (g_status.wrapped  ||  g_status.key_pending) {
  504.                   g_status.key_pending = FALSE;
  505.                   g_status.wrapped = FALSE;
  506.                   show_search_message( CLR_SEARCH, g_display.mode_color );
  507.                }
  508.  
  509.                /*
  510.                 * while there are no errors or Control-Breaks, let's keep on
  511.                 *  executing a macro.  g_status.control_break is a global
  512.                 *  editor flag that is set in our Control-Break interrupt
  513.                 *  handler routine.
  514.                 */
  515.                if (g_status.control_break == TRUE) {
  516.                   rc = ERROR;
  517.                   break;
  518.                }
  519.  
  520.                /*
  521.                 * we haven't called any editor function yet.  we need
  522.                 *  to look at the editor command that is to be executed.
  523.                 *  if the command is PlayBack, we need to break out of
  524.                 *  this inner do loop and start executing the macro
  525.                 *  from the beginning (the outer do loop).
  526.                 *
  527.                 * if we don't break out now from a recursive macro, we will
  528.                 *  recursively call PlayBack and we will likely overflow
  529.                 *  the main (as opposed to the macro_stack) stack.
  530.                 */
  531.                if (g_status.command == PlayBack) {
  532.  
  533.                   /*
  534.                    * recursive macros are handled differently from
  535.                    *  macros that call other macros.
  536.                    * recursive macros - break out of this inner loop
  537.                    *  and begin executing the macro from the beg of macro.
  538.                    * standard macros - save the next instruction of this
  539.                    *  macro on the stack and begin executing the called macro.
  540.                    */
  541.                   if (g_status.current_macro != g_status.key_pressed) {
  542.                      if (push_macro_stack(
  543.                                    macro.strokes[g_status.macro_next].next )
  544.                                    != OK) {
  545.                         error( WARNING, window->bottom_line, ed16 );
  546.                         rc = ERROR;
  547.                      }
  548.                      g_status.macro_next =
  549.                                 macro.first_stroke[g_status.key_pressed-256];
  550.                      g_status.current_macro = g_status.key_pressed;
  551.                      key = macro.strokes[g_status.macro_next].key;
  552.  
  553.                      /*
  554.                       * execute called macro at beginning of this do loop.
  555.                       */
  556.                      continue;
  557.                   } else
  558.  
  559.                      /*
  560.                       * recursive macro - break out of this inner loop
  561.                       *  or else we may overflow the stack(s).
  562.                       */
  563.                      break;
  564.                }
  565.  
  566.  
  567.                /*
  568.                 * just as we assert before the main editor routine, let's
  569.                 *  assert in the macro function to make sure everything
  570.                 *  is everything.
  571.                 */
  572. #if defined(  __MSC__ )
  573.                assert( window != NULL );
  574.                assert( window->file_info != NULL );
  575.                assert( window->file_info->line_list != NULL );
  576.                assert( window->file_info->line_list_end != NULL );
  577.                assert( window->file_info->line_list_end->len == EOF );
  578.                assert( window->visible == TRUE );
  579.                assert( window->rline >= 0 );
  580.                assert( window->rline <= window->file_info->length + 1 );
  581.                assert( window->rcol >= 0 );
  582.                assert( window->rcol < MAX_LINE_LENGTH );
  583.                assert( window->ccol >= window->start_col );
  584.                assert( window->ccol <= window->end_col );
  585.                assert( window->bcol >= 0 );
  586.                assert( window->bcol < MAX_LINE_LENGTH );
  587.                assert( window->bcol == window->rcol-(window->ccol - window->start_col) );
  588.                assert( window->start_col >= 0 );
  589.                assert( window->start_col < window->end_col );
  590.                assert( window->end_col < g_display.ncols );
  591.                assert( window->cline >= window->top_line );
  592.                assert( window->cline <= window->bottom_line );
  593.                assert( window->top_line > 0 );
  594.                assert( window->top_line <= window->bottom_line );
  595.                assert( window->bottom_line < MAX_LINES );
  596.                assert( window->bin_offset >= 0 );
  597.                if (window->ll->next == NULL)
  598.                   assert( window->ll->len == EOF );
  599.                else
  600.                   assert( window->ll->len >= 0 );
  601.                assert( window->ll->len <  MAX_LINE_LENGTH );
  602. #endif
  603.  
  604.  
  605.                if (g_status.command >= 0 && g_status.command < NUM_FUNCS)
  606.                    rc = (*do_it[g_status.command])( window );
  607.                g_status.macro_next =
  608.                           macro.strokes[g_status.macro_next].next;
  609.             } while (rc == OK  &&  g_status.macro_next != -1);
  610.  
  611.             /*
  612.              * if we have come the end of a macro definition and there
  613.              *  are no keys saved on the stack, we have finished our
  614.              *  macro.  get out.
  615.              */
  616.             if (g_status.macro_next == -1 && g_status.mstack_pointer < 0)
  617.                rc = ERROR;
  618.             else if (rc != ERROR  &&  g_status.mstack_pointer >= 0) {
  619.  
  620.                /*
  621.                 * if this is a recursive macro, don't pop the stack
  622.                 *  because we didn't push.
  623.                 * for a standard macro, get back the next key in the
  624.                 *  calling macro.
  625.                 */
  626.                if (g_status.current_macro != g_status.key_pressed) {
  627.                   if (pop_macro_stack( &g_status.macro_next ) != OK) {
  628.                      error( WARNING, window->bottom_line, ed17 );
  629.                      rc = ERROR;
  630.                   } else {
  631.                      popped = TRUE;
  632.                      key = macro.strokes[g_status.macro_next].key;
  633.                   }
  634.                }
  635.             }
  636.          }
  637.       }
  638.       g_status.macro_executing = FALSE;
  639.    }
  640.    return( OK );
  641. }
  642.  
  643.  
  644. /*
  645.  * Name:    push_macro_stack
  646.  * Purpose: push the next key in a currently executing macro on local stack
  647.  * Date:    October 31, 1992
  648.  * Notes:   finally got tired of letting macros only "jump" and not call
  649.  *           other macros.
  650.  *          the first time in, stack_pointer is -1.
  651.  */
  652. int  push_macro_stack( int key )
  653. {
  654.    /*
  655.     * first, make sure we have room to push the key.
  656.     */
  657.    if (g_status.mstack_pointer+1 < MAX_KEYS) {
  658.  
  659.       /*
  660.        * increment the stack pointer and store the pointer to the next key
  661.        *  of the currently executing macro.  store the currently executing
  662.        *  macro, too.
  663.        */
  664.       ++g_status.mstack_pointer;
  665.       macro_stack[g_status.mstack_pointer].key = key;
  666.       macro_stack[g_status.mstack_pointer].macro = g_status.current_macro;
  667.       return( OK );
  668.    } else
  669.       return( STACK_OVERFLOW );
  670. }
  671.  
  672.  
  673. /*
  674.  * Name:    pop_macro_stack
  675.  * Purpose: pop currently executing macro on local stack
  676.  * Date:    October 31, 1992
  677.  * Notes:   finally got tired of letting macros only "jump" and not "call"
  678.  *           other macros.
  679.  *          pop the macro stack.  stack pointer is pointing to last key saved
  680.  *           on stack.
  681.  */
  682. int  pop_macro_stack( int *key )
  683. {
  684.  
  685.    /*
  686.     * before we pop the stack, make sure there is something in the stack.
  687.     */
  688.    if (g_status.mstack_pointer >= 0) {
  689.  
  690.       /*
  691.        * pop the pointer to the next key and the current macro, then
  692.        *  decrement the stack_pointer.
  693.        */
  694.       *key = macro_stack[g_status.mstack_pointer].key;
  695.       g_status.current_macro = macro_stack[g_status.mstack_pointer].macro;
  696.       --g_status.mstack_pointer;
  697.       return( OK );
  698.    } else
  699.       return( STACK_UNDERFLOW );
  700. }
  701.  
  702.  
  703. /*
  704.  * Name:    Pause
  705.  * Purpose: Enter pause state for macros
  706.  * Date:    June 5, 1992
  707.  * Passed:  arg_filler:  argument to satify function prototype
  708.  * Returns: ERROR if the ESC key was pressed, OK otherwise.
  709.  * Notes:   this little function is quite useful in macro definitions.  if
  710.  *          it is called near the beginning of a macro, the user may decide
  711.  *          whether or not to stop the macro.
  712.  */
  713. int  pause( WINDOW *arg_filler )
  714. {
  715. int  c;
  716.  
  717.    /*
  718.     * tell user we are paused.  the '|  0x80' turns on the blink attribute
  719.     */
  720.    s_output( paused1, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  721.    s_output( paused2, g_display.mode_line, 23+strlen( paused1 ),
  722.              g_display.mode_color );
  723.  
  724.    /*
  725.     * get the user's response and restore the mode line.
  726.     */
  727.    c = getkey( );
  728.    show_modes( );
  729.    if (mode.record == TRUE) {
  730.       /*
  731.        * if recording a macro, show recording message
  732.        */
  733.       s_output( main15, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  734.       show_avail_strokes( );
  735.    }
  736.    return( c == ESC ? ERROR : OK );
  737. }
  738.